package repeater

import (
    "encoding/json"
    "io/ioutil"
    "strings"
    "time"
    "fmt"
)

type DB interface {
    Prepare(string, int64, ReportMetric, float64) error
    Commit() error
    ShouldClose(int64) bool
    Close() error //file name
    Init(string) error
    ////
    Range() ([]string, error)
    ShouldDrop(int64) bool
    Clean(string) error
    Drop() error
    ValuesFor(string) (DataSet, error)
}

const (
    DESCNAME = "__META__"
)

type DBMeta struct {
    From           int64
    To             int64
    Count          int64
    Day            int
    Ip             map[string]bool
    LastWriteTime  int64
    LastActiveTime int64
    InitialTime    int64
}

func (d *DBMeta) handleClean(ip string) error {
    contain, ok := d.Ip[ip]
    if !ok {
        return fmt.Errorf("clean error: data not existed")
    }
    if !contain {
        return fmt.Errorf("clean error: data already cleaned")
    }
    d.Ip[ip] = false
    return nil
}
func (d *DBMeta) handleAdd(ip string, o int64) error {
    if d.From == 0 || d.From > o {
        d.From = o
    }
    if d.To == 0 || d.To < o {
        d.To = o
    }
    contained, ok := d.Ip[ip]
    if !ok {
        d.Ip[ip] = true
    }
    if ok && !contained { //already marked as false
        return fmt.Errorf("add error: data already cleaned")
    }
    d.Count += 1
    d.LastWriteTime = time.Now().Unix()
    return nil
}

func NewDBMeta(content []byte, day int) *DBMeta {
    d := &DBMeta{
        InitialTime: time.Now().Unix(),
        Ip:          make(map[string]bool),
    }
    if len(content) != 0 {
        json.Unmarshal(content, d)
    }
    if d.Day == 0 {
        d.Day = day
    }
    return d
}

func (d *DBMeta) KeyValue() ([]byte, []byte, error) {
    v, err := json.Marshal(d)
    return []byte(DESCNAME), v, err
}

type Filter struct {
    BlackList []string `json:"black_list"`
    WhiteList []string `json:"white_list"`
}

func (f *Filter) pass(metric string) bool {
    if len(f.WhiteList) != 0 {
        for _, s := range f.WhiteList {
            if strings.Contains(metric, s) {
                return true
            }
        }
        return false
    }
    for _, s := range f.BlackList {
        if strings.Contains(metric, s) {
            return false
        }
    }
    return true
}

func LoadFilter(fn string) (*Filter, error) {
    nf := &Filter{[]string{}, []string{}}
    c, err := ioutil.ReadFile(fn)
    if err != nil {
        return nil, err
    }
    if err := json.Unmarshal(c, nf); err != nil {
        return nil, err
    }
    return nf, nil
}
